#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <stdexcept>

#include <hcDebug.hpp>

/*
    //1.配置命令规范(进行一次)
    //	多组命令
    //      分隔符不要用/t,会识别错误
    string s1 = "dump -a %%s 111 -b -s %%s 222 -n %%d 333\n"
        "ping -a %%s AAA -b -s %%s sss -n %%d 444 -t %%d 555\n"
        "pid -pid %%d\n"
        ;
    hcInputCommandEasy cmd;
    cmd.Config_Multi(s1, "\n");

    //2.输入命令(比如临时手动输入)
    string str2 = "ping -a \"aa bb cc\" -b -s sssss -n 10000 -t 0x12345";

    //输入命令匹配到那一组命令,并且
    //	并且把值填充进去,便于后面直接方便的使用
    cmd.input(str2);

    

*/




using namespace std;

// 辅助函数声明（实现略）
//vector<string> command2words(string all_words);
//int str2int(const string& str);
//vector<string> split_noempty(const string& s, const string& sep);
// 假设这些函数已经实现
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <iostream>
#include <sstream>

using namespace std;

// 辅助函数声明
vector<string> command2words(string all_words);
int str2int(const string& str);
vector<string> split_noempty(const string& s, const string& sep);

class hcInputCommandEasy {
public:
    void Config_Multi(const string& config, const string& separator) {
        vector<string> commands = split_noempty(config, separator);
        for (const string& cmd : commands) {
            vector<string> tokens = split_noempty(cmd, " ");
            if (tokens.empty()) continue;

            CommandTemplate tpl;
            tpl.name = tokens[0];
            bool valid = true;
            size_t i = 1;

            while (i < tokens.size() && valid) {
                if (tokens[i][0] == '-') {
                    ParamTemplate param;
                    param.flag = tokens[i].substr(1);
                    i++;

                    //printf("name=%s\n", param.flag.c_str());

                    // 检查类型说明符
                    if (i < tokens.size()) {
                        if (tokens[i] == "%%s") {
                            param.type = ParamTemplate::STR;
                            i++;
                            param.required = true;

                            // 处理默认值
                            if (i < tokens.size() && tokens[i][0] != '-') {
                                param.default_str = parse_quoted(tokens[i]);
                                param.required = false;
                                i++;
                            }
                        }
                        else if (tokens[i] == "%%d") {
                            param.type = ParamTemplate::INT;
                            i++;
                            param.required = true;

                            // 处理默认值
                            if (i < tokens.size() && tokens[i][0] != '-') {
                                try {
                                    param.default_int = stoi(tokens[i], nullptr, 0);
                                    param.required = false;
                                    i++;
                                }
                                catch (...) {
                                    error_log("Invalid integer default: " + tokens[i]);
                                    valid = false;
                                }
                            }
                        }
                        else {
                            // BOOL类型
                            param.type = ParamTemplate::BOOL;
                            param.required = false;
                        }
                        //printf("name=%s, %d\n", param.flag.c_str(), param.required);
                    }
                    else {
                        // BOOL类型
                        param.type = ParamTemplate::BOOL;
                        param.required = false;
                        //printf("name=%s, %d\n", param.flag.c_str(), param.required);
                    }
                    

                    // 验证后续token的有效性
                    if (i < tokens.size() && tokens[i][0] != '-') {
                        error_log("Unexpected value after parameter: " + param.flag);
                        valid = false;
                    }

                    // 防止重复参数
                    if (tpl.params.count(param.flag)) {
                        error_log("Duplicate parameter: " + param.flag);
                        valid = false;
                    }

                    if (valid) tpl.params[param.flag] = param;
                }
                else {
                    error_log("Unexpected token: " + tokens[i]);
                    valid = false;
                }
            }

            if (valid) {
                templates_.push_back(tpl);
            }
            else {
                error_log("Invalid command template: " + cmd);
            }
        }
    }

    void Config_One(const string& config)
    {
        string config2 = "default " + config;
        Config_Multi(config2, "\n");
    }
    bool input(int argc, char** argv)
    {
        hcDebug::Output(">>> input\n");
        string strall;
        for (int i = 0; i < argc; i++) {
            
            string str3 = argv[i];
            if (str3.find(" ") == string::npos)
            {
                str3 = argv[i];
            }
            else
            {
                str3 = "\"" + str3 + "\"";
            }
            if (strall == "")
            {
                strall = "default ";
            }
            else
            {
                strall += str3;
                strall += " ";
                hcDebug::Output(">>> input %s\n", str3.c_str());
            }

        }
        hcDebug::Output(">>> %s\n", strall.c_str());

        return input(strall);
    }

    bool input(const string& command) {
        values_.clear();
        vector<string> words = command2words(command);
        if (words.empty()) {
            error_log("Empty command");
            return false;
        }

        string cmdName = words[0];
        vector<string> args(words.begin() + 1, words.end());

        for (const auto& tpl : templates_) {
            if (tpl.name != cmdName) continue;

            map<string, Value> tmpValues;
            map<string, bool> foundFlags;
            bool valid = true;
            size_t i = 0;

            while (i < args.size() && valid) {
                if (args[i][0] == '-') {
                    string flag = args[i].substr(1);
                    auto paramIt = tpl.params.find(flag);
                    if (paramIt == tpl.params.end()) {
                        error_log("Unknown parameter: " + flag);
                        valid = false;
                        break;
                    }

                    const auto& param = paramIt->second;
                    if (foundFlags.count(flag)) {
                        error_log("Duplicate parameter: " + flag);
                        valid = false;
                        break;
                    }

                    foundFlags[flag] = true;

                    if (param.type == ParamTemplate::BOOL) {
                        tmpValues[flag] = { true, 0, "" };
                        i++;
                    }
                    else {
                        if (++i >= args.size()) {
                            error_log("Missing value for parameter: " + flag);
                            valid = false;
                            break;
                        }

                        string value = args[i];
                        try {
                            if (param.type == ParamTemplate::STR) {
                                tmpValues[flag] = { false, 0, parse_quoted(value) };
                            }
                            else {
                                tmpValues[flag] = { false, stoi(value, nullptr, 0), "" };
                            }
                        }
                        catch (...) {
                            error_log("Invalid value for parameter: " + flag + " (" + value + ")");
                            valid = false;
                            break;
                        }
                        i++;
                    }
                }
                else {
                    error_log("Unexpected positional argument: " + args[i]);
                    valid = false;
                    break;
                }
            }

            // 验证必填参数
            if (valid) {
                for (const auto& param_pair : tpl.params) {
                    const string& flag = param_pair.first;
                    const ParamTemplate& param = param_pair.second;

                    //printf(">>> %s,%d", param.flag.c_str(), param.required);

                    if (param.required && foundFlags.find(flag) == foundFlags.end()) {
                        error_log("Missing required parameter: " + flag);
                        valid = false;
                    }
                }
            }

            // 设置默认值
            if (valid) {
                for (const auto& param_pair : tpl.params) {
                    const string& flag = param_pair.first;
                    const ParamTemplate& param = param_pair.second;
                    if (foundFlags.find(flag) == foundFlags.end()) {
                        Value val;
                        val.bool_val = false;
                        val.int_val = 0;

                        if (param.type == ParamTemplate::STR) {
                            val.str_val = param.default_str;
                        }
                        else if (param.type == ParamTemplate::INT) {
                            val.int_val = param.default_int;
                        }

                        tmpValues[flag] = val;
                    }
                }
                values_ = tmpValues;
                return true;
            }
        }
        return false;
    }

    // 获取参数值的接口保持不变
    string get_str(const string& flag) const {
        auto it = values_.find(flag);
        return (it != values_.end() && !it->second.str_val.empty()) ?
            it->second.str_val : "";
    }

    bool get_bool(const string& flag) const {
        auto it = values_.find(flag);
        return (it != values_.end()) ? it->second.bool_val : false;
    }

    int get_int(const string& flag) const {
        auto it = values_.find(flag);
        return (it != values_.end()) ? it->second.int_val : 0;
    }

private:
    struct ParamTemplate {
        enum Type { BOOL, STR, INT };
        string flag;
        Type type;
        bool required = true;
        string default_str;
        int default_int = 0;
    };

    struct CommandTemplate {
        string name;
        map<string, ParamTemplate> params;
    };

    struct Value {
        bool bool_val;
        int int_val;
        string str_val;
    };

    vector<CommandTemplate> templates_;
    map<string, Value> values_;

    void error_log(const string& msg) const {
        //cerr << "[hcInputCommand] ERROR: " << msg << endl;
        hcDebug::Output("[hcInputCommand] ERROR: %s", msg.c_str());
    }

    static string parse_quoted(const string& s) {
        if (s.size() >= 2 && s.front() == '"' && s.back() == '"') {
            return s.substr(1, s.size() - 2);
        }
        return s;
    }
};

// 辅助函数实现(有bug,无法处理中文)
vector<string> command2words(string all_words) {
    vector<string> words;
    string word;
    bool inQuote = false;

    for (char c : all_words) {
        if (c == '"') {
            inQuote = !inQuote;
            if (!inQuote && !word.empty()) {
                words.push_back(word);
                word.clear();
            }
        }
        else if (isspace(c) && !inQuote) {
            if (!word.empty()) {
                words.push_back(word);
                word.clear();
            }
        }
        else {
            word += c;
        }
    }

    if (!word.empty()) {
        words.push_back(word);
    }
    return words;
}

vector<string> split_noempty(const string& s, const string& sep) {
    vector<string> tokens;
    size_t start = 0, end;

    while ((end = s.find(sep, start)) != string::npos) {
        if (end != start) {
            tokens.push_back(s.substr(start, end - start));
        }
        start = end + sep.length();
    }

    if (start < s.length()) {
        tokens.push_back(s.substr(start));
    }

    return tokens;
}